// +build !windows

//Package nginx ...
package nginx

import (
	"errors"
	"fmt"
	"os/exec"
	"strings"
	"syscall"
)

//NewNginxClient 创建一个操作Nginx的客户端实例
func NewNginxClient() *Nginx {
	path := getNginxPath()
	return &Nginx{
		Pid:     getNginxPid(),
		IsExist: path != "",
		Nginx:   path,
		Config:  getNginxConfig(),
	}
}

func getNginxPid() string {
	return ""
}

func getNginxPath() string {
	cmd := exec.Command("which", "nginx")
	output, err := cmd.Output()
	if err != nil {
		return ""
	}
	// 因为结果是字节数组，需要转换成string
	path := string(output)
	return strings.Replace(path, "\n", "", 1)
}

//getNginxConfig nginx的配置文件路径
func getNginxConfig() string {
	_, config := ConfigValid()
	return config
}

//ConfigValid 验证Config的有效性
func ConfigValid() (bool, string) {
	test := exec.Command("nginx", "-t")
	testResult, err := test.CombinedOutput()
	if err != nil {
		fmt.Println(err.Error())
		return false, ""
	}
	fmt.Println(string(testResult))
	r := string(testResult)
	rs := strings.Split(r, " ")
	count := len(rs)
	testRet := strings.Contains(r, "test is successful")
	config := rs[count-4]
	return testRet, config
}

//Nginx ..
type Nginx struct {
	IsExist bool   //Nginx 是否安装
	Pid     string // Nginx PID文件
	Nginx   string // Nginx 可执行文件
	Config  string //Nginx 配置文件
}

//Result ..
type Result struct {
	Code int32        `json:"code"`
	Msg  string       `json:"msg"`
	Data *interface{} `json:"data"`
}

//ReverseProxyConfig 反向代理
func (c *Nginx) ReverseProxyConfig(serverName string, listen string, proxyPass string) string {
	conf :=
		`server {
		listen %s;
		server_name %s;
		location / {
			proxy_pass %s;			
			proxy_redirect https://$host/ https://$http_host/;
			proxy_set_header X-Real-IP $remote_addr;
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
			proxy_set_header Host $host;
		}		
	}`
	return fmt.Sprintf(conf, listen, serverName, proxyPass)
}

//AddReverseProxyConfig 添加反向代理
func (c *Nginx) AddReverseProxyConfig(serverName string, listen string, proxyPass string) {

}

//Status 获取 Nginx 状态 @return *Status, error
func (c *Nginx) Status() (*Status, error) {
	pid, err := getPid(c)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	process := new(Process)
	proc, perr := process.New(int32(pid))
	if perr != nil {
		return nil, perr
	}
	p := &Status{
		PID:      proc.Pid,
		CPU:      float32(proc.Cpu()),
		Memory:   proc.Memory(),
		Status:   proc.Status(),
		Start:    proc.StartDateTime(),
		Time:     proc.Time(),
		Host:     proc.Host(),
		IPAddrs:  proc.Internal(),
		Subpid:   proc.Children(),
		Networks: proc.Networks(),
	}
	return p, err
}

//Start 启动 Nginx 服务
func (c *Nginx) Start() (bool, error) {
	status, _ := c.Status()
	if status != nil {
		return true, errors.New("Nginx服务已经启动")
	}
	// 测试文档
	test, terr := c.Test()
	if false == test {
		return false, terr
	}
	start := exec.Command("/bin/sh", "-c", c.Nginx)
	startResult, err := start.CombinedOutput()
	if string(startResult) != "" {
		return false, errors.New("nginx starting Result: \n" + string(startResult))
	}
	if err != nil {
		return false, errors.New("Start error: " + err.Error())
	}
	return true, nil
}

//Reload 重载 Nginx 服务
func (c *Nginx) Reload() (bool, error) {
	status, _ := c.Status()
	if status == nil {
		return c.Start()
	}
	test, terr := c.Test()
	if false == test {
		return false, terr
	}
	pid := status.PID
	err := syscall.Kill(int(pid), syscall.SIGHUP)
	if err != nil {
		return false, err
	}
	return true, nil
}

//Stop 停止 Nginx 服务
func (c *Nginx) Stop() (bool, error) {
	status, _ := c.Status()
	if 0 >= status.PID {
		return true, nil
	}
	stop := exec.Command("/bin/sh", "-c", c.Nginx+" -s stop")
	stopResult, err := stop.CombinedOutput()
	if string(stopResult) != "" {
		return false, errors.New("nginx stopped Result:\n" + string(stopResult))
	}
	if err != nil {
		return false, errors.New("nginx -s stop Error: \n" + (err.Error()))
	}
	return true, nil
}

//Test 测试 Nginx 配置文件
func (c *Nginx) Test() (bool, error) {
	test := exec.Command("/bin/sh", "-c", c.Nginx+" -t")
	testResult, err := test.CombinedOutput()
	if err != nil {
		return false, err
	}
	r := string(testResult)
	fmt.Println(r)
	result := "nginx testing result:\n" + r
	if !strings.Contains(r, "successful") {
		return false, errors.New(result)
	}
	return true, nil
}
